package com.andy.blog.common.utils;

import com.andy.blog.common.constant.BaseConstants;
import com.andy.blog.common.utils.ip.IpUtils;
import io.vavr.Tuple;
import io.vavr.Tuple4;
import io.vavr.Tuple5;
import io.vavr.Tuple6;
import io.vavr.Tuple7;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.FileSystem;
import oshi.software.os.OSFileStore;
import oshi.software.os.OperatingSystem;
import oshi.util.Util;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * Created by andy on 2023-04-15 12:44
 */
public class SystemInfoUtils {

    private SystemInfoUtils() {}

    /**
     * 休眠时间
     */
    private static final int OSHI_WAIT_SECOND = 1000;
    private static final double FORMAT = 1024.0;
    private static final SystemInfo systemInfo = new SystemInfo();
    private static final HardwareAbstractionLayer hardware = systemInfo.getHardware();
    private static final OperatingSystem operatingSystem = systemInfo.getOperatingSystem();

    /**
     * cpu信息
     */
    public static Tuple6<Integer, String, String, String, String, Long> getCpuInfo() {
        CentralProcessor processor = hardware.getProcessor();
        long[] prevTicks = processor.getSystemCpuLoadTicks();
        Util.sleep(OSHI_WAIT_SECOND);

        long[] ticks = processor.getSystemCpuLoadTicks();
        long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()];
        long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
        long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
        long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
        long cSys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
        long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()];
        long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
        long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()];
        long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;

        // cpu核数
        int cpuNum = processor.getLogicalProcessorCount();
        // cpu系统使用率
        String sys = new DecimalFormat(BaseConstants.MATH_POUND_KEY).format(cSys * 1.0 / totalCpu);
        // cpu用户使用率
        String use = new DecimalFormat(BaseConstants.MATH_POUND_KEY).format(user * 1.0 / totalCpu);
        // cpu当前等待率
        String wait = new DecimalFormat(BaseConstants.MATH_POUND_KEY).format(iowait * 1.0 / totalCpu);
        // cpu当前使用率
        String free = new DecimalFormat(BaseConstants.MATH_POUND_KEY).format(1.0 - (idle * 1.0 / totalCpu));

        return Tuple.of(cpuNum, sys, use, wait, free, totalCpu);
    }

    /**
     * 系统jvm信息
     */
    public static Tuple7<String, String, String, String, String, String, String> getJvmInfo() {
        Properties props = System.getProperties();
        Runtime runtime = Runtime.getRuntime();
        long jvmTotalMemoryByte = runtime.totalMemory();
        long freeMemoryByte = runtime.freeMemory();

        // jvm总内存
        String total = formatByte(runtime.totalMemory());
        // 空闲空间
        String free = formatByte(runtime.freeMemory());
        // jvm最大可申请
        String max = formatByte(runtime.maxMemory());
        // jvm已使用内存
        String user = formatByte(jvmTotalMemoryByte - freeMemoryByte);
        // jvm内存使用率
        String usageRate = new DecimalFormat(BaseConstants.MATH_POUND_KEY).format((jvmTotalMemoryByte - freeMemoryByte) * 1.0 / jvmTotalMemoryByte);
        // jdk版本
        String jdkVersion = props.getProperty("java.version");
        // jdk路径
        String jdkHome = props.getProperty("java.home");

        return Tuple.of(total, max, free, jdkVersion, jdkHome, user, usageRate);
    }


    /**
     * 系统内存信息
     */
    public static Tuple4<String, String, String, String> getMemInfo() {
        GlobalMemory memory = systemInfo.getHardware().getMemory();
        // 总内存
        long totalByte = memory.getTotal();
        // 剩余
        long availableByte = memory.getAvailable();
        // 总内存
        String total = formatByte(totalByte);
        // 使用
        String used = formatByte(totalByte - availableByte);
        // 剩余内存
        String free = formatByte(availableByte);
        // 使用率
        String usageRate = new DecimalFormat(BaseConstants.MATH_POUND_KEY).format((totalByte - availableByte) * 1.0 / totalByte);

        return Tuple.of(total, used, free, usageRate);
    }

    /**
     * 系统盘符信息
     */
    public static List<Map<String, Object>> getSysFileInfo() {
        List<Map<String, Object>> sysFiles = new ArrayList<>();
        FileSystem fileSystem = operatingSystem.getFileSystem();
        List<OSFileStore> fileStores = fileSystem.getFileStores();
        for (OSFileStore fs : fileStores) {
            long free = fs.getUsableSpace();
            long total = fs.getTotalSpace();
            long used = total - free;
            Map<String, Object> cpuInfo = new HashMap<>();
            // 盘符路径
            cpuInfo.put("dirName", fs.getMount());
            // 盘符类型
            cpuInfo.put("sysTypeName", fs.getType());
            // 文件类型
            cpuInfo.put("typeName", fs.getName());
            // 总大小
            cpuInfo.put("total", formatByte(total));
            // 剩余大小
            cpuInfo.put("free", formatByte(free));
            // 已经使用量
            cpuInfo.put("used", formatByte(used));
            //            // 资源的使用率
            cpuInfo.put("usage", DoubleUtils.mul(DoubleUtils.div(used, total, 4), 100));
            sysFiles.add(cpuInfo);
        }
        return sysFiles;
    }

    /**
     * 系统信息
     */
    public static Tuple5<String, String, String, String, String> getSysInfo() {
        Properties props = System.getProperties();
        // 操作系统名
        String osName = props.getProperty("os.name");
        // 系统架构
        String osArch = props.getProperty("os.arch");
        // 服务器名称
        String computerName = IpUtils.getHostName();
        // 服务器Ip
        String computerIp = IpUtils.getHostIp();
        // 项目路径
        String userDir = props.getProperty("user.dir");

        return Tuple.of(osName, osArch, computerIp, computerName, userDir);
    }

    /**
     * 所有系统信息
     */
    public static Map<String, Object> getInfo() {
        Map<String, Object> info = new HashMap<>();
        info.put("cpuInfo", getCpuInfo());
        info.put("jvmInfo", getJvmInfo());
        info.put("memInfo", getMemInfo());
        info.put("sysInfo", getSysInfo());
        info.put("sysFileInfo", getSysFileInfo());
        return info;
    }

    /**
     * 单位转换
     */
    private static String formatByte(long byteNumber) {
        //换算单位
        double kbNumber = byteNumber / FORMAT;
        if (kbNumber < FORMAT) {
            return new DecimalFormat("#.##KB").format(kbNumber);
        }
        double mbNumber = kbNumber / FORMAT;
        if (mbNumber < FORMAT) {
            return new DecimalFormat("#.##MB").format(mbNumber);
        }
        double gbNumber = mbNumber / FORMAT;
        if (gbNumber < FORMAT) {
            return new DecimalFormat("#.##GB").format(gbNumber);
        }
        double tbNumber = gbNumber / FORMAT;
        return new DecimalFormat("#.##TB").format(tbNumber);
    }
}
